package com.emergency.evaluate.domain;

/**  系统打分利用最小二乘法，设置数值对应分数点，进行曲线拟合获取相应分值
 * Created by Administrator on 2020/5/19.
 */
public class LeastSquareMethod {


        private double[] x;
        private double[] y;
        private double[] weight;
        private int n;
        private double[] coefficient;

        /*构建*/
        public LeastSquareMethod(double[] x, double[] y, int n) {
            if (x == null || y == null || x.length < 2 || x.length != y.length
                    || n < 2) {
                throw new IllegalArgumentException(
                        "IllegalArgumentException occurred.");
            }
            this.x = x;
            this.y = y;
            this.n = n;
            weight = new double[x.length];
            for (int i = 0; i < x.length; i++) {
                weight[i] = 1;
            }
            compute();
        }



        //系数向量矩阵
        public double[] getCoefficient() {
            return coefficient;
        }

        //计算分数
        public double fit(double x) {
            if (coefficient == null) {
                return 0;
            }
            double sum = 0;
            for (int i = 0; i < coefficient.length; i++) {
                sum += Math.pow(x, i) * coefficient[i];
            }
            return sum;
        }




        //X 的转置矩阵
        private double calcReciprocal(double x) {
            if (coefficient == null) {
                return 0;
            }
            double sum = 0;
            for (int i = 1; i < coefficient.length; i++) {
                sum += i * Math.pow(x, i - 1) * coefficient[i];
            }
            return sum;
        }

        //确定线性方程组的各个系数
        private void compute() {
            if (x == null || y == null || x.length <= 1 || x.length != y.length
                    || x.length < n || n < 2) {
                return;
            }
            double[] s = new double[(n - 1) * 2 + 1];
            for (int i = 0; i < s.length; i++) {
                for (int j = 0; j < x.length; j++) {
                    s[i] += Math.pow(x[j], i) * weight[j];
                }
            }
            double[] b = new double[n];
            for (int i = 0; i < b.length; i++) {
                for (int j = 0; j < x.length; j++) {
                    b[i] += Math.pow(x[j], i) * y[j] * weight[j];
                }
            }
            double[][] a = new double[n][n];
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    a[i][j] = s[i + j];
                }
            }
            coefficient = calcLinearEquation(a, b);
        }

    //系数向量矩阵
        private double[] calcLinearEquation(double[][] a, double[] b) {
            if (a == null || b == null || a.length == 0 || a.length != b.length) {
                return null;
            }
            for (double[] x : a) {
                if (x == null || x.length != a.length)
                    return null;
            }

            int len = a.length - 1;
            double[] result = new double[a.length];

            if (len == 0) {
                result[0] = b[0] / a[0][0];
                return result;
            }

            double[][] aa = new double[len][len];
            double[] bb = new double[len];
            int posx = -1, posy = -1;
            for (int i = 0; i <= len; i++) {
                for (int j = 0; j <= len; j++)
                    if (a[i][j] != 0.0d) {
                        posy = j;
                        break;
                    }
                if (posy != -1) {
                    posx = i;
                    break;
                }
            }
            if (posx == -1) {
                return null;
            }

            int count = 0;
            for (int i = 0; i <= len; i++) {
                if (i == posx) {
                    continue;
                }
                bb[count] = b[i] * a[posx][posy] - b[posx] * a[i][posy];
                int count2 = 0;
                for (int j = 0; j <= len; j++) {
                    if (j == posy) {
                        continue;
                    }
                    aa[count][count2] = a[i][j] * a[posx][posy] - a[posx][j]
                            * a[i][posy];
                    count2++;
                }
                count++;
            }

            // Calculate sub linear equation
            double[] result2 = calcLinearEquation(aa, bb);

            // After sub linear calculation, calculate the current coefficient
            double sum = b[posx];
            count = 0;
            for (int i = 0; i <= len; i++) {
                if (i == posy) {
                    continue;
                }
                sum -= a[posx][i] * result2[count];
                result[i] = result2[count];
                count++;
            }
            result[posy] = sum / a[posx][posy];
            return result;
        }


    }

